Reactã§ã®å¹ççãªãããã°ãå®çŸããœãŒã¹ãããã®ä»çµã¿ãã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ãšã®é£æºãéçºã»æ¬çªç°å¢ã§ã®æŽ»çšæ³ã解説ã
Reactãšã©ãŒãããã°ããã¹ã¿ãŒããïŒãšã©ãŒäœçœ®è¿œè·¡ã®ããã®ã³ã³ããŒãã³ããœãŒã¹ãããã®è©³çްãªè§£èª¬
Reactéçºè
ã§ããã°ããã©ãŠã¶ã®ã³ã³ãœãŒã«ã«è¡šç€ºããããmain.chunk.js:1:84325ã®ãããªã巚倧ã§minifyãããJavaScriptãã¡ã€ã«å
ã®äžå¯è§£ãªè¡ãæãã¯ãªãã£ã«ã«ãªãšã©ãŒã¡ãã»ãŒãžã«ãééããªãééããããšãããã§ãããããã®åäžè¡ã®ãã£ãŒãããã¯ã¯ããŸãã§ããšã³ãžã³ã®ã©ããã«åé¡ãããããšåãããããããªãã®ã§ãããã©ã¹ãã¬ãŒã·ã§ã³ãããŸããæéãããããéçºã©ã€ããµã€ã¯ã«ã«ããã倧ããªããã«ããã¯ãšãªããŸããããã§ãçŸä»£ã®Webéçºã®åœ±ã®è±éããœãŒã¹ãããã®ç»å Žã§ãã
ãã®ã¬ã€ãã§ã¯ãReactã³ã³ããŒãã³ããšã©ãŒãœãŒã¹ãããã®äžçãæ·±ãæãäžããŸãããœãŒã¹ãããã®ä»çµã¿ããšã©ãŒäœçœ®è¿œè·¡ã«äžå¯æ¬ ãªçç±ãéçºç°å¢ãšæ¬çªç°å¢ã®äž¡æ¹ã§å¹æçã«æ§æããæ¹æ³ãè§£ãæãããŸããæçµçã«ã¯ãé£è§£ãªãšã©ãŒã¡ãã»ãŒãžããå ·äœçã§å®è·µçãªãããã°ã®æŽå¯ã«å€ããããã®ç¥èã身ã«ã€ããããšãã§ããŸãã
ãœãŒã¹ããããšã¯æ£ç¢ºã«ã¯äœã§ããïŒ
åºæ¬çã«ã¯ããœãŒã¹ãããã¯ãã³ã³ãã€ã«ãminifyããã³ãã«ãããã³ãŒããšãããªããæžããå
ã®ãœãŒã¹ã³ãŒããšã®ã€ãªãããäœãåºããã¡ã€ã«ïŒéåžžã¯.mapæ¡åŒµåãä»ããŠããŸãïŒã§ããè©³çŽ°ãªæç€ºã»ãããŸãã¯ç¿»èš³ããŒãšèããŠãã ããããã©ãŠã¶ãã³ãŒããå®è¡ãã倿ããããã¡ã€ã«ã®ç¹å®ã®è¡ãšåã§ãšã©ãŒãçºçããå ŽåããœãŒã¹ãããã䜿çšããŠãã®å Žæãæ€çŽ¢ãããšã©ãŒãå
ã®ã人éãèªãããã¡ã€ã«ã§æ£ç¢ºã«ã©ãã§çºçããããæããŠãããŸãã
çŸä»£ã®Webéçºããã»ã¹ã«ã¯ãããã€ãã®å€æã¹ããããå«ãŸããŸãã
- Transpilation: Babelã®ãããªããŒã«ã¯ãã¢ãã³JavaScriptïŒESNextïŒãšJSXããå€ããããåºãäºææ§ã®ããJavaScriptïŒES5ãªã©ïŒã«å€æããŸããããšãã°ãããªãã®ãšã¬ã¬ã³ããªJSX
<div>Hello</div>ã¯ãReact.createElement('div', null, 'Hello')ã«ãªããŸãã - Bundling: WebpackãViteãRollupãªã©ã®ããŒã«ã¯ããã¹ãŠã®åã ã®ã¢ãžã¥ãŒã«ïŒã³ã³ããŒãã³ãããŠãŒãã£ãªãã£ãCSSãã¡ã€ã«ïŒãååŸãããã©ãŠã¶ãããŠã³ããŒãããããã®ããã€ãã®æé©åããããã¡ã€ã«ã«çµåããŸãã
- Minification: ãã¡ã€ã«ãµã€ãºãåæžããèªã¿èŸŒã¿æéãæ¹åããããã«ãTerserãUglifyJSã®ãããªããŒã«ã¯ã倿°åãçããã空çœãåé€ããã³ã¡ã³ããåé€ããŸããããªãã®èšè¿°çãªå€æ°
const userProfileData = ...ã¯ãconst a = ...ã«ãªããããããŸããã
ãããã®ã¹ãããã¯ããã©ãŒãã³ã¹ã«äžå¯æ¬ ã§ããããããã°ã®ããã«å ã®ã³ãŒãã®æ§é ãšå¯èªæ§ãç Žå£ããŸãããœãŒã¹ãããã¯ããã®é£èªåãé転ãããéçºè ãšã¯ã¹ããªãšã³ã¹ã管çå¯èœã«ããŸãã
ãªããœãŒã¹ããããReactéçºã§å¿ é ãªã®ã
Reactã®ã³ã³ããŒãã³ãããŒã¹ã®ã¢ãŒããã¯ãã£ã¯ããœãŒã¹ããããããã«éèŠã«ããå¥ã®è€éãã®å±€ã远å ããŸãããšã©ãŒã¯ãã¡ã€ã«å ã§çºçããã ãã§ãªããç¹å®ã®ã³ã³ããŒãã³ãå ã§çºçããå€ãã®å Žåãä»ã®ã³ã³ããŒãã³ãã®éå±€å ã§çºçããŸãããœãŒã¹ãããããªããšããããã°ã¯æªå€¢ã«ãªããŸãã
ã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ã®å
React 16以åã§ã¯ãéåžžã®ãšã©ãŒã¯ãminifyããããã³ãã«å ã®é¢æ°åŒã³åºãã®ãªã¹ãã§ããæšæºã®JavaScriptã¹ã¿ãã¯ãã¬ãŒã¹ãæäŸããŠããŸãããããããšã©ãŒã®åå ãšãªã£ãã³ã³ããŒãã³ãã«è¿œè·¡ããããšã¯å°é£ã§ããã
React 16ã§ã¯ãã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ãšããç»æçãªæ©èœãå°å ¥ãããŸããããšã©ãŒãçºçãããšãReactã¯ãœãŒã¹ããããšé£æºããŠããšã©ãŒã«ã€ãªããã³ã³ããŒãã³ãã®éå±€ã瀺ãã¹ã¿ãã¯ãã¬ãŒã¹ãæäŸããŸããæå³ã®ãªã颿°åãèŠã代ããã«ãããªããæžããå®éã®ã³ã³ããŒãã³ãåã衚瀺ãããŸãã
é©åãªãœãŒã¹ããããŸãã¯ã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ããªãå Žåã®äŸïŒ
Uncaught TypeError: Cannot read properties of null (reading 'name')
at a (main.chunk.js:1:84325)
at Ko (main.chunk.js:1:115219)
at ys (main.chunk.js:1:98734)
ãœãŒã¹ããããšã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ãããå Žåã®äŸïŒ
Uncaught TypeError: Cannot read properties of null (reading 'name')
at UserProfile (UserProfile.jsx:15:25)
at div
at ProfilePage (ProfilePage.jsx:32:10)
at App (App.jsx:8:5)
2çªç®ã®äŸã®æ¹ãã¯ããã«åœ¹ç«ã¡ãŸãããšã©ãŒãUserProfileã³ã³ããŒãã³ãã®15è¡ç®ã§çºçããããšãããã«ããããŸããããã¯ProfilePageã«ãã£ãŠã¬ã³ããªã³ã°ãããããã«Appã«ãã£ãŠã¬ã³ããªã³ã°ãããŸãããããã¯ãææ°ã®ãããã°ãèŠæ±ããæ£ç¢ºãªäœçœ®è¿œè·¡ã§ãã
Reactãããžã§ã¯ãã§ã®ãœãŒã¹ãããã®èšå®
幞ããªããšã«ãã»ãšãã©ã®ææ°ã®ReactããŒã«ãã§ãŒã³ã«ã¯ãããã«äœ¿ããé©åãªãœãŒã¹ãããæ§æãä»å±ããŠããŸãããã ããç°ãªãç°å¢ã«åãããŠããããå¶åŸ¡ããæ¹æ³ãçè§£ããããšããèšå®ãæé©åããããã®éµã§ãã
Create React AppïŒCRAïŒ
Create React Appã䜿çšããŠããå Žåã¯ã幞éã§ããéçºç°å¢ïŒnpm startïŒã§é«å質ã®ãœãŒã¹ããããèªåçã«çæããŸããæ¬çªãã«ãïŒnpm run buildïŒã®å ŽåããœãŒã¹ããããçæãããŸããã.envãã¡ã€ã«ã§ç°å¢å€æ°ãèšå®ããããšã«ãããã»ãã¥ãªãã£äžã®çç±ããããããç¡å¹ã«ããããšãã§ããŸãã
GENERATE_SOURCEMAP=false
æ¬çªç°å¢ã§ã®ãœãŒã¹ãããã®äœ¿çšã®é·æãšçæã«ã€ããŠã¯ãåŸã§èª¬æããŸãã
Vite
人æ°ã®ããæ¬¡äžä»£ãã«ãããŒã«ã§ããViteããåªããããã«äœ¿ãããµããŒããæäŸããŸããé«éã§å¹æçãªãããã°ãšã¯ã¹ããªãšã³ã¹ã®ããã«ãããã©ã«ãã§éçºã§ãœãŒã¹ãããã䜿çšããŸããæ¬çªãã«ãã®å Žåãvite.config.jsãã¡ã€ã«ã§åºåãå¶åŸ¡ã§ããŸãã
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
// ... other config
build: {
sourcemap: true, // or 'hidden', or false
},
})
ãã«ãæ§æã§sourcemap: trueãèšå®ãããšãæ¬çªã³ãŒãã®ãœãŒã¹ããããçæããããªã³ã¯ãããŸãã
ã«ã¹ã¿ã Webpackæ§æ
ã«ã¹ã¿ã Webpackèšå®ã管çããŠããå Žåã¯ãäž»ãªå¶åŸ¡ã¯webpack.config.jsã®devtoolããããã£ã§ãããã®ããããã£ã«ã¯å€ãã®å¯èœãªå€ããããããããããã«ãé床ãšãœãŒã¹ãããã®å質ã®éã§ç°ãªããã¬ãŒããªããæäŸããŸãã
- éçºçšïŒ
eval-source-mapïŒé«å質ã®ãœãŒã¹ããããåã¢ãžã¥ãŒã«ã¯eval()ã§å®è¡ããããœãŒã¹ããããDataURLãšããŠè¿œå ãããŸãããããã°ã«ã¯åªããŠããŸãããåæãã«ãã§ã¯é ããªãå¯èœæ§ããããŸããcheap-module-source-mapïŒè¯ããã©ã³ã¹ãå ã®ãœãŒã¹ã³ãŒããããã³ã°ïŒè¡çªå·ã®ã¿ãåçªå·ãªãïŒãæäŸããeval-source-mapãããé«éã§ããããã¯ãéçºã«æšå¥šãããéžæè¢ã§ããããšããããããŸãã
- æ¬çªçšïŒ
source-mapïŒæé«å質ãåå¥ã®.mapãã¡ã€ã«ãçæããŸããããã¯ãæ¬çªãããã°ã«æé©ãªãªãã·ã§ã³ã§ããããã«ãã«æéãããããŸãããœãŒã¹ãããã¯ããã³ãã«ãã¡ã€ã«å ã®ã³ã¡ã³ããä»ããŠãªã³ã¯ãããŠããããã©ãŠã¶ã®éçºè ããŒã«ããã¢ã¯ã»ã¹ã§ããŸããhidden-source-mapïŒsource-mapãšåãã§ããããã³ãã«ã«ãªã³ãã³ã°ã³ã¡ã³ãã远å ããŸããããã©ãŠã¶ã®éçºè ããŒã«ã§ã¯èªåçã«èŠã€ãããŸãããããã¯ããœãŒã¹ãããããããªãã¯ã«å ¬éããããšãªããïŒSentryãBugsnagãªã©ïŒãšã©ãŒè¿œè·¡ãµãŒãã¹ã«ã¢ããããŒããããå Žåã«æé©ãªãªãã·ã§ã³ã§ããfalseïŒãœãŒã¹ãããã¯çæãããŸããã
äžè¬çãªãããã§ãã·ã§ãã«èšå®ã¯æ¬¡ã®ããã«ãªããŸãã
// webpack.config.js
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
// ... other config
devtool: isProduction ? 'hidden-source-map' : 'cheap-module-source-map',
};
};
ãœãŒã¹ãããã䜿çšããReactãšã©ãŒã®ãã³ãŒãïŒå®è·µçãªãŠã©ãŒã¯ã¹ã«ãŒ
ãããå®éã«èŠãŠã¿ãŸãããããŠãŒã¶ãŒã®è©³çްã衚瀺ããããã«èšèšãããã³ã³ããŒãã³ãããããããã°ãããããšãæ³åããŠãã ããã
ãã°ã®ããã³ã³ããŒãã³ãïŒ`UserDetails.jsx`
import React from 'react';
function UserDetails({ user }) {
// The bug: user.profile can sometimes be null
const bio = user.profile.bio;
return (
<div>
<h2>{user.name}</h2>
<p>{bio}</p>
</div>
);
}
export default UserDetails;
user.profileãnullã§ããuserãªããžã§ã¯ãã䜿çšããŠãã®ã³ã³ããŒãã³ããã¬ã³ããªã³ã°ããããšãã¢ããªã±ãŒã·ã§ã³ãã¯ã©ãã·ã¥ããŸãã
ãããã°ãšã¯ã¹ããªãšã³ã¹
- ãšã©ãŒã衚瀺ãããŸãïŒãã©ãŠã¶ã®ã³ã³ãœãŒã«ã«ã¯ã
Uncaught TypeError: Cannot read properties of null (reading 'bio')ã®ãããªãšã©ãŒã衚瀺ãããŸãã - ãœãŒã¹ããããªãã§ã®äœçœ®è¿œè·¡ïŒã¹ã¿ãã¯ãã¬ãŒã¹ã¯ãminifyããããã¡ã€ã«
main.js:1:12345ãæããŸãããã®ãªã³ã¯ãã¯ãªãã¯ãããšãèªããªãã³ãŒãã®å£ãéããåé¡ãã©ãããçºçããã®ãæšæž¬ããããšã«ãªããŸãã - ãœãŒã¹ãããã䜿çšããäœçœ®è¿œè·¡ïŒãšã¯ã¹ããªãšã³ã¹ã¯ãŸã£ããç°ãªããŸãã
- ã¹ã¿ãã¯ãã¬ãŒã¹ã¯æç¢ºã§èªã¿ããããªããŸãïŒ
at UserDetails (UserDetails.jsx:5)ã UserDetailsãã¬ã³ããªã³ã°ãã芪ã³ã³ããŒãã³ãã瀺ãå®å šãªã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ã衚瀺ãããŸãã- ãã¡ã€ã«å
UserDetails.jsx:5ã¯ãã¯ãªãã¯å¯èœãªãªã³ã¯ã§ãããããã¯ãªãã¯ãããšããã©ãŠã¶ã®éçºè ããŒã«å ã®ãå ã®ãçŸãããã©ãŒããããããUserDetails.jsxãã¡ã€ã«ã®5è¡ç®ã«çŽæ¥ç§»åããŸããæ£ç¢ºãªåŒuser.profile.bioã匷調衚瀺ãããããšããããããŸãã
- ã¹ã¿ãã¯ãã¬ãŒã¹ã¯æç¢ºã§èªã¿ããããªããŸãïŒ
ãã®å³æçãªãæ£ç¢ºãªãã£ãŒãããã¯ã«ãŒãã¯ããããã°æéãæ°æéããæ°åã«ãå Žåã«ãã£ãŠã¯æ°ç§ã«ççž®ããŸããuser.profileã«ã¢ã¯ã»ã¹ããåã«ãuser.profileã®ãã§ãã¯ã远å ããå¿
èŠãããããšãããã«ããããŸãã
æ¬çªç°å¢ã§ã®ãœãŒã¹ãããïŒå€§ããªè°è«
ãœãŒã¹ãããã¯éçºã«ã¯æããã«æå¹ã§ãããæ¬çªç°å¢ã§ã®äœ¿çšã¯ããããã°å¯èœæ§ãšã»ãã¥ãªãã£ã®ãã¬ãŒããªããå«ãããã埮åŠãªè©±é¡ã§ãã
æ¬çªãœãŒã¹ãããã®å©ç¹
æ¬çªç°å¢ã¯ãæãéèŠãªãã°ãçºçããå Žæã§ãããœãŒã¹ãããããªããšããŠãŒã¶ãŒãèªå远跡ãµãŒãã¹ããåŸããããšã©ãŒã¬ããŒãã¯minifyãããã»ãšãã©åœ¹ã«ç«ã¡ãŸãããå®éã®ãŠãŒã¶ãŒã«åœ±é¿ãäžããåé¡ã广çã«ãããã°ããã«ã¯ããããã®æ¬çªã¹ã¿ãã¯ãã¬ãŒã¹ãé£èªåè§£é€ããæ¹æ³ãå¿ èŠã§ãã
æ¬çªãœãŒã¹ãããã®æ¬ ç¹
- ã»ãã¥ãªãã£ãšç¥ç財ç£ïŒãœãŒã¹ããããå
¬éïŒ
source-mapdevtoolãªãã·ã§ã³ã䜿çšïŒãããšããã©ãŠã¶ãæã£ãŠãã人ã¯èª°ã§ãã¢ããªã±ãŒã·ã§ã³ã®å ã®ãœãŒã¹ã³ãŒããç°¡åã«æ€æ»ã§ããŸããããã«ãããããžãã¹ããžãã¯ãAPIããŒïŒäžé©åã«åŠçãããŠããå ŽåïŒããŸãã¯ãã®ä»ã®ç¬èªã®æ å ±ãå ¬éãããå¯èœæ§ããããŸãã - ããã©ãŒãã³ã¹ïŒææ°ã®ãã©ãŠã¶ã¯ãDevToolsãéããŠããå Žåã«ã®ã¿ãœãŒã¹ããããã¡ã€ã«ãèªã¿èŸŒã¿ãŸãããããããçæãããšããã«ãæéãå¢å ããå¯èœæ§ããããŸãã
äž¡æ¹ã®é·æã掻ããïŒå®å šãªæ¬çªãããã°
幞ããªããšã«ãã»ãã¥ãªãã£ãšãããã°å¯èœæ§ã®ã©ã¡ãããéžæããå¿ èŠã¯ãããŸãããææ°ã®ãã¹ããã©ã¯ãã£ã¹ã¯ãæ¬çªç°å¢ã§ãœãŒã¹ããããçæããããããããéå ¬éã«ããããšã§ãã
hidden-source-mapïŒãŸãã¯åçïŒã䜿çšããïŒãã³ãã©ãŒãæ§æããŠããœãŒã¹ããããçæããŸãããJavaScriptãã¡ã€ã«ã«ãªã³ã¯ããªãããã«ããŸããããã«ããããã©ãŠã¶ãèªåçã«ããããèŠã€ããããšããªããªããŸãã- ãšã©ãŒè¿œè·¡ãµãŒãã¹ãçµ±åããïŒSentryãBugsnagãDatadogãLogRocketãªã©ã®ãµãŒãã¹ã䜿çšããŸãããããã®ãã©ãããã©ãŒã ã¯ãã¢ããªã±ãŒã·ã§ã³ãšã©ãŒãæåããŠåæããããã«èšèšãããŠããŸãã
- CI/CDäžã«ãœãŒã¹ããããã¢ããããŒãããïŒç¶ç¶çã€ã³ãã°ã¬ãŒã·ã§ã³ãšãããã€ã¡ã³ããã€ãã©ã€ã³ã®äžç°ãšããŠãã¢ããªã±ãŒã·ã§ã³ããã«ãããåŸãçæããã
.mapãã¡ã€ã«ããéžæãããšã©ãŒè¿œè·¡ãµãŒãã¹ã«çŽæ¥ã¢ããããŒãããæé ã远å ããŸããã»ãšãã©ã®ãµãŒãã¹ã¯ããããè¡ãããã®CLIããŒã«ãæäŸããŠããŸããCI / CDã¹ã¯ãªããã¯ãæŠå¿µçã«ã¯æ¬¡ã®ããã«ãªããŸãã# 1. Install dependencies npm install # 2. Build the application (this generates JS bundles and .map files) GENERATE_SOURCEMAP=true npm run build # 3. Upload source maps to your service sentry-cli releases files <release-version> upload-sourcemaps ./build/static/js # 4. Deploy your application (the .map files are NOT deployed to public servers) deploy_to_production ./build
ãã®èšå®ã§ã¯ãæ¬çªç°å¢ã§ãšã©ãŒãçºçãããšããšã©ãŒã¬ããŒãã远跡ãµãŒãã¹ã«éä¿¡ãããŸããæ¬¡ã«ããµãŒãã¹ã¯ãã¢ããããŒãããéå ¬éã®ãœãŒã¹ãããã䜿çšããŠã¹ã¿ãã¯ãã¬ãŒã¹ã®é£èªåãè§£é€ããæ¬çªãã°ã®å®å šã§èªã¿ãããã³ã³ããŒãã³ãã¹ã¿ãã¯ãã¬ãŒã¹ãããœãŒã¹ã³ãŒããå ¬éããããšãªãæäŸããŸãã
çµè«ïŒæ··ä¹±ããæçããž
ãœãŒã¹ãããã¯ãReactã䜿çšããææ°ã®ã³ã³ããŒãã³ãããŒã¹ã®éçºãå¯èœã«ããã ãã§ãªããå¿«é©ã«ããåºç€ãšãªããã¯ãããžãŒã§ãããã©ãŠã¶ãå®è¡ããæé©åãããã³ãŒããšãããªããæžãèªã¿ãããã³ãŒããšã®éã®ã®ã£ãããåãããšã©ãŒã¡ãã»ãŒãžãé£è§£ãªããºã«ããæç¢ºãªæšèã«å€ããŸãã
éçºéåºŠãšæ¬çªç°å¢ã®ã»ãã¥ãªãã£ã®äž¡æ¹ã«å¯Ÿå¿ããããã«æ§æããæ¹æ³ãçè§£ããããšã«ãããããªããšããªãã®ããŒã ã¯ãæ£ç¢ºãã€å¹ççã«ãšã©ãŒã远跡ã§ããããã«ãªããŸããç¹ã«ãšã©ãŒè¿œè·¡ãµãŒãã¹ãšçµã¿åããããå ç¢ãªãœãŒã¹ãããæŠç¥ãæ¡çšããããšã¯ãReactã¢ããªã±ãŒã·ã§ã³ã®å®å®æ§ãšä¿å®æ§ã«æè³ã§ããæãéèŠãªããšã®1ã€ã§ããæšæž¬ããããŠãæç¢ºã«ãããã°ãéå§ããŸãããã